; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=avr -mattr=movw -verify-machineinstrs | FileCheck %s

define i32 @shl_i32_1(i32 %a) {
; CHECK-LABEL: shl_i32_1:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsl r22
; CHECK-NEXT:    rol r23
; CHECK-NEXT:    rol r24
; CHECK-NEXT:    rol r25
; CHECK-NEXT:    ret
  %res = shl i32 %a, 1
  ret i32 %res
}

define i32 @shl_i32_2(i32 %a) {
; CHECK-LABEL: shl_i32_2:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsl r22
; CHECK-NEXT:    rol r23
; CHECK-NEXT:    rol r24
; CHECK-NEXT:    rol r25
; CHECK-NEXT:    lsl r22
; CHECK-NEXT:    rol r23
; CHECK-NEXT:    rol r24
; CHECK-NEXT:    rol r25
; CHECK-NEXT:    ret
  %res = shl i32 %a, 2
  ret i32 %res
}

define i32 @shl_i32_4(i32 %a) {
; CHECK-LABEL: shl_i32_4:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    swap r25
; CHECK-NEXT:    andi r25, 240
; CHECK-NEXT:    swap r24
; CHECK-NEXT:    eor r25, r24
; CHECK-NEXT:    andi r24, 240
; CHECK-NEXT:    eor r25, r24
; CHECK-NEXT:    swap r23
; CHECK-NEXT:    eor r24, r23
; CHECK-NEXT:    andi r23, 240
; CHECK-NEXT:    eor r24, r23
; CHECK-NEXT:    swap r22
; CHECK-NEXT:    eor r23, r22
; CHECK-NEXT:    andi r22, 240
; CHECK-NEXT:    eor r23, r22
; CHECK-NEXT:    ret
  %res = shl i32 %a, 4
  ret i32 %res
}

; shift four bits and then shift one bit
define i32 @shl_i32_5(i32 %a) {
; CHECK-LABEL: shl_i32_5:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    swap r25
; CHECK-NEXT:    andi r25, 240
; CHECK-NEXT:    swap r24
; CHECK-NEXT:    eor r25, r24
; CHECK-NEXT:    andi r24, 240
; CHECK-NEXT:    eor r25, r24
; CHECK-NEXT:    swap r23
; CHECK-NEXT:    eor r24, r23
; CHECK-NEXT:    andi r23, 240
; CHECK-NEXT:    eor r24, r23
; CHECK-NEXT:    swap r22
; CHECK-NEXT:    eor r23, r22
; CHECK-NEXT:    andi r22, 240
; CHECK-NEXT:    eor r23, r22
; CHECK-NEXT:    lsl r22
; CHECK-NEXT:    rol r23
; CHECK-NEXT:    rol r24
; CHECK-NEXT:    rol r25
; CHECK-NEXT:    ret
  %res = shl i32 %a, 5
  ret i32 %res
}

; shift two to the right and move the registers around
define i32 @shl_i32_6(i32 %a) {
; CHECK-LABEL: shl_i32_6:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    mov r18, r1
; CHECK-NEXT:    ror r18
; CHECK-NEXT:    lsr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    ror r18
; CHECK-NEXT:    mov r25, r24
; CHECK-NEXT:    mov r24, r23
; CHECK-NEXT:    mov r19, r22
; CHECK-NEXT:    movw r22, r18
; CHECK-NEXT:    ret
  %res = shl i32 %a, 6
  ret i32 %res
}


; shift one to the right and move registers around
define i32 @shl_i32_7(i32 %a) {
; CHECK-LABEL: shl_i32_7:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    mov r18, r1
; CHECK-NEXT:    ror r18
; CHECK-NEXT:    mov r25, r24
; CHECK-NEXT:    mov r24, r23
; CHECK-NEXT:    mov r19, r22
; CHECK-NEXT:    movw r22, r18
; CHECK-NEXT:    ret
  %res = shl i32 %a, 7
  ret i32 %res
}

define i32 @shl_i32_8(i32 %a) {
; CHECK-LABEL: shl_i32_8:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    mov r25, r24
; CHECK-NEXT:    mov r24, r23
; CHECK-NEXT:    mov r23, r22
; CHECK-NEXT:    mov r22, r1
; CHECK-NEXT:    ret
  %res = shl i32 %a, 8
  ret i32 %res
}

define i32 @shl_i32_9(i32 %a) {
; CHECK-LABEL: shl_i32_9:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsl r22
; CHECK-NEXT:    rol r23
; CHECK-NEXT:    rol r24
; CHECK-NEXT:    mov r25, r24
; CHECK-NEXT:    mov r24, r23
; CHECK-NEXT:    mov r23, r22
; CHECK-NEXT:    mov r22, r1
; CHECK-NEXT:    ret
  %res = shl i32 %a, 9
  ret i32 %res
}

; shift 3 of 4 registers and move the others around
define i32 @shl_i32_12(i32 %a) {
; CHECK-LABEL: shl_i32_12:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    swap r24
; CHECK-NEXT:    andi r24, 240
; CHECK-NEXT:    swap r23
; CHECK-NEXT:    eor r24, r23
; CHECK-NEXT:    andi r23, 240
; CHECK-NEXT:    eor r24, r23
; CHECK-NEXT:    swap r22
; CHECK-NEXT:    eor r23, r22
; CHECK-NEXT:    andi r22, 240
; CHECK-NEXT:    eor r23, r22
; CHECK-NEXT:    mov r25, r24
; CHECK-NEXT:    mov r24, r23
; CHECK-NEXT:    mov r23, r22
; CHECK-NEXT:    mov r22, r1
; CHECK-NEXT:    ret
  %res = shl i32 %a, 12
  ret i32 %res
}

define i32 @shl_i32_15(i32 %a) {
; CHECK-LABEL: shl_i32_15:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    movw r18, r22
; CHECK-NEXT:    lsr r24
; CHECK-NEXT:    ror r19
; CHECK-NEXT:    ror r18
; CHECK-NEXT:    mov r23, r1
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    mov r22, r1
; CHECK-NEXT:    movw r24, r18
; CHECK-NEXT:    ret
  %res = shl i32 %a, 15
  ret i32 %res
}

; This is a special case: this shift is performed directly inside SelectionDAG
; instead of as a custom lowering like the other shift operations.
define i32 @shl_i32_16(i32 %a) {
; CHECK-LABEL: shl_i32_16:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    movw r24, r22
; CHECK-NEXT:    ldi r22, 0
; CHECK-NEXT:    ldi r23, 0
; CHECK-NEXT:    ret
  %res = shl i32 %a, 16
  ret i32 %res
}

; Combined with the register allocator, shift instructions can sometimes be
; optimized away entirely. The least significant registers are simply stored
; directly instead of moving them first.
define void @shl_i32_16_ptr(i32 %a, ptr %ptr) {
; CHECK-LABEL: shl_i32_16_ptr:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    movw r30, r20
; CHECK-NEXT:    std Z+2, r22
; CHECK-NEXT:    std Z+3, r23
; CHECK-NEXT:    ldi r24, 0
; CHECK-NEXT:    ldi r25, 0
; CHECK-NEXT:    st Z, r24
; CHECK-NEXT:    std Z+1, r25
; CHECK-NEXT:    ret
  %res = shl i32 %a, 16
  store i32 %res, ptr %ptr
  ret void
}

; shift only the most significant byte and then move it
define i32 @shl_i32_28(i32 %a) {
; CHECK-LABEL: shl_i32_28:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    swap r22
; CHECK-NEXT:    andi r22, 240
; CHECK-NEXT:    mov r25, r22
; CHECK-NEXT:    mov r24, r1
; CHECK-NEXT:    mov r23, r1
; CHECK-NEXT:    mov r22, r1
; CHECK-NEXT:    ret
  %res = shl i32 %a, 28
  ret i32 %res
}

; move the rightmost bit to the leftmost bit and clear the rest
define i32 @shl_i32_31(i32 %a) {
; CHECK-LABEL: shl_i32_31:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsr r22
; CHECK-NEXT:    mov r25, r1
; CHECK-NEXT:    ror r25
; CHECK-NEXT:    mov r24, r1
; CHECK-NEXT:    mov r23, r1
; CHECK-NEXT:    mov r22, r1
; CHECK-NEXT:    ret
  %res = shl i32 %a, 31
  ret i32 %res
}

define i32 @lshr_i32_1(i32 %a) {
; CHECK-LABEL: lshr_i32_1:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    ret
  %res = lshr i32 %a, 1
  ret i32 %res
}

define i32 @lshr_i32_2(i32 %a) {
; CHECK-LABEL: lshr_i32_2:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    lsr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    ret
  %res = lshr i32 %a, 2
  ret i32 %res
}

define i32 @lshr_i32_4(i32 %a) {
; CHECK-LABEL: lshr_i32_4:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    swap r22
; CHECK-NEXT:    andi r22, 15
; CHECK-NEXT:    swap r23
; CHECK-NEXT:    eor r22, r23
; CHECK-NEXT:    andi r23, 15
; CHECK-NEXT:    eor r22, r23
; CHECK-NEXT:    swap r24
; CHECK-NEXT:    eor r23, r24
; CHECK-NEXT:    andi r24, 15
; CHECK-NEXT:    eor r23, r24
; CHECK-NEXT:    swap r25
; CHECK-NEXT:    eor r24, r25
; CHECK-NEXT:    andi r25, 15
; CHECK-NEXT:    eor r24, r25
; CHECK-NEXT:    ret
  %res = lshr i32 %a, 4
  ret i32 %res
}

define i32 @lshr_i32_6(i32 %a) {
; CHECK-LABEL: lshr_i32_6:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsl r22
; CHECK-NEXT:    rol r23
; CHECK-NEXT:    rol r24
; CHECK-NEXT:    rol r25
; CHECK-NEXT:    mov r19, r1
; CHECK-NEXT:    rol r19
; CHECK-NEXT:    lsl r22
; CHECK-NEXT:    rol r23
; CHECK-NEXT:    rol r24
; CHECK-NEXT:    rol r25
; CHECK-NEXT:    rol r19
; CHECK-NEXT:    mov r22, r23
; CHECK-NEXT:    mov r23, r24
; CHECK-NEXT:    mov r18, r25
; CHECK-NEXT:    movw r24, r18
; CHECK-NEXT:    ret
  %res = lshr i32 %a, 6
  ret i32 %res
}

define i32 @lshr_i32_7(i32 %a) {
; CHECK-LABEL: lshr_i32_7:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsl r22
; CHECK-NEXT:    rol r23
; CHECK-NEXT:    rol r24
; CHECK-NEXT:    rol r25
; CHECK-NEXT:    mov r19, r1
; CHECK-NEXT:    rol r19
; CHECK-NEXT:    mov r22, r23
; CHECK-NEXT:    mov r23, r24
; CHECK-NEXT:    mov r18, r25
; CHECK-NEXT:    movw r24, r18
; CHECK-NEXT:    ret
  %res = lshr i32 %a, 7
  ret i32 %res
}

define i32 @lshr_i32_8(i32 %a) {
; CHECK-LABEL: lshr_i32_8:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    mov r22, r23
; CHECK-NEXT:    mov r23, r24
; CHECK-NEXT:    mov r24, r25
; CHECK-NEXT:    mov r25, r1
; CHECK-NEXT:    ret
  %res = lshr i32 %a, 8
  ret i32 %res
}

define i32 @lshr_i32_9(i32 %a) {
; CHECK-LABEL: lshr_i32_9:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    mov r22, r23
; CHECK-NEXT:    mov r23, r24
; CHECK-NEXT:    mov r24, r25
; CHECK-NEXT:    mov r25, r1
; CHECK-NEXT:    ret
  %res = lshr i32 %a, 9
  ret i32 %res
}

define i32 @lshr_i32_16(i32 %a) {
; CHECK-LABEL: lshr_i32_16:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    movw r22, r24
; CHECK-NEXT:    ldi r24, 0
; CHECK-NEXT:    ldi r25, 0
; CHECK-NEXT:    ret
  %res = lshr i32 %a, 16
  ret i32 %res
}

define i32 @lshr_i32_24(i32 %a) {
; CHECK-LABEL: lshr_i32_24:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    mov r22, r25
; CHECK-NEXT:    mov r23, r1
; CHECK-NEXT:    mov r24, r1
; CHECK-NEXT:    mov r25, r1
; CHECK-NEXT:    ret
  %res = lshr i32 %a, 24
  ret i32 %res
}

define i32 @lshr_i32_31(i32 %a) {
; CHECK-LABEL: lshr_i32_31:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsl r25
; CHECK-NEXT:    mov r22, r1
; CHECK-NEXT:    rol r22
; CHECK-NEXT:    mov r23, r1
; CHECK-NEXT:    mov r24, r1
; CHECK-NEXT:    mov r25, r1
; CHECK-NEXT:    ret
  %res = lshr i32 %a, 31
  ret i32 %res
}

define i32 @ashr_i32_1(i32 %a) {
; CHECK-LABEL: ashr_i32_1:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    asr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    ret
  %res = ashr i32 %a, 1
  ret i32 %res
}

define i32 @ashr_i32_2(i32 %a) {
; CHECK-LABEL: ashr_i32_2:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    asr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    asr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    ret
  %res = ashr i32 %a, 2
  ret i32 %res
}

; can't use the swap/andi/eor trick here
define i32 @ashr_i32_4(i32 %a) {
; CHECK-LABEL: ashr_i32_4:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    asr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    asr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    asr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    asr r25
; CHECK-NEXT:    ror r24
; CHECK-NEXT:    ror r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    ret
  %res = ashr i32 %a, 4
  ret i32 %res
}

define i32 @ashr_i32_7(i32 %a) {
; CHECK-LABEL: ashr_i32_7:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsl r22
; CHECK-NEXT:    rol r23
; CHECK-NEXT:    rol r24
; CHECK-NEXT:    rol r25
; CHECK-NEXT:    sbc r19, r19
; CHECK-NEXT:    mov r22, r23
; CHECK-NEXT:    mov r23, r24
; CHECK-NEXT:    mov r18, r25
; CHECK-NEXT:    movw r24, r18
; CHECK-NEXT:    ret
  %res = ashr i32 %a, 7
  ret i32 %res
}

; TODO: this could be optimized to 4 movs, instead of 5.
define i32 @ashr_i32_8(i32 %a) {
; CHECK-LABEL: ashr_i32_8:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    mov r19, r25
; CHECK-NEXT:    lsl r19
; CHECK-NEXT:    sbc r19, r19
; CHECK-NEXT:    mov r22, r23
; CHECK-NEXT:    mov r23, r24
; CHECK-NEXT:    mov r18, r25
; CHECK-NEXT:    movw r24, r18
; CHECK-NEXT:    ret
  %res = ashr i32 %a, 8
  ret i32 %res
}

define i32 @ashr_i32_16(i32 %a) {
; CHECK-LABEL: ashr_i32_16:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    movw r22, r24
; CHECK-NEXT:    lsl r25
; CHECK-NEXT:    sbc r25, r25
; CHECK-NEXT:    mov r24, r25
; CHECK-NEXT:    ret
  %res = ashr i32 %a, 16
  ret i32 %res
}

define i32 @ashr_i32_17(i32 %a) {
; CHECK-LABEL: ashr_i32_17:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    movw r22, r24
; CHECK-NEXT:    lsl r25
; CHECK-NEXT:    sbc r25, r25
; CHECK-NEXT:    asr r23
; CHECK-NEXT:    ror r22
; CHECK-NEXT:    mov r24, r25
; CHECK-NEXT:    ret
  %res = ashr i32 %a, 17
  ret i32 %res
}

define i32 @ashr_i32_22(i32 %a) {
; CHECK-LABEL: ashr_i32_22:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsl r24
; CHECK-NEXT:    rol r25
; CHECK-NEXT:    sbc r18, r18
; CHECK-NEXT:    lsl r24
; CHECK-NEXT:    rol r25
; CHECK-NEXT:    mov r19, r18
; CHECK-NEXT:    mov r23, r18
; CHECK-NEXT:    rol r23
; CHECK-NEXT:    mov r22, r25
; CHECK-NEXT:    movw r24, r18
; CHECK-NEXT:    ret
  %res = ashr i32 %a, 22
  ret i32 %res
}

define i32 @ashr_i32_23(i32 %a) {
; CHECK-LABEL: ashr_i32_23:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsl r24
; CHECK-NEXT:    rol r25
; CHECK-NEXT:    sbc r23, r23
; CHECK-NEXT:    mov r22, r25
; CHECK-NEXT:    mov r24, r23
; CHECK-NEXT:    mov r25, r23
; CHECK-NEXT:    ret
  %res = ashr i32 %a, 23
  ret i32 %res
}

define i32 @ashr_i32_30(i32 %a) {
; CHECK-LABEL: ashr_i32_30:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsl r25
; CHECK-NEXT:    sbc r23, r23
; CHECK-NEXT:    lsl r25
; CHECK-NEXT:    mov r22, r23
; CHECK-NEXT:    rol r22
; CHECK-NEXT:    mov r24, r23
; CHECK-NEXT:    mov r25, r23
; CHECK-NEXT:    ret
  %res = ashr i32 %a, 30
  ret i32 %res
}

define i32 @ashr_i32_31(i32 %a) {
; CHECK-LABEL: ashr_i32_31:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    lsl r25
; CHECK-NEXT:    sbc r22, r22
; CHECK-NEXT:    mov r23, r22
; CHECK-NEXT:    movw r24, r22
; CHECK-NEXT:    ret
  %res = ashr i32 %a, 31
  ret i32 %res
}
